{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Домашнее задание к лекции \"Функции\"\n",
    "\n",
    "Вам нужно помочь секретарю автоматизировать работу. Для этого нужно написать программу, которая будет на основе хранимых данных исполнять пользовательские команды.\n",
    "\n",
    "Общие требования к программе:\n",
    "\n",
    "- код должен быть грамотно декомпозирован (каждая функция отвечает за свою конкретную задачу, дублирующийся функционал переиспользуется, а его код не повторяется);\n",
    "- в коде отсутствуют глобальные переменные (за исключением documents и directories);\n",
    "- пользовательский ввод обрабатывается в цикле while до тех пор, пока пользователь явно не завершит программу (вводом команды \"q\")."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Введите команду [q - выход]: l\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 11-2, тип: invoice, владелец: Геннадий Покемонов, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 2\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: p\n",
      "Введите номер документа: 7721\n",
      "Документ не найден в базе\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: p\n",
      "Введите номер документа: 2207 876234\n",
      "Владелец документа: Василий Гупкин\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: s\n",
      "Введите номер документа: 7745\n",
      "Документ не найден в базе\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: s\n",
      "Введите номер документа: 10006\n",
      "Номер полки: 2\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: as\n",
      "Введите номер полки: 2\n",
      "Такая полка уже существует. Текущий перечень полок: 1, 2, 3\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: as\n",
      "Введите номер полки: 10\n",
      "Полка добавлена. Текущий перечень полок: 1, 2, 3, 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: ds\n",
      "Введите номер полки: 1\n",
      "На полке есть документы, удалите их перед удалением полки. Текущий перечень полок: 1, 2, 3, 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: ds\n",
      "Введите номер полки: 3\n",
      "Полка удалена. Текущий перечень полок: 1, 2, 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: ds\n",
      "Введите номер полки: 67\n",
      "Такой полки не существует. Текущий перечень полок: 1, 2, 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: ad\n",
      "Введите номер документа: 28965\n",
      "Введите тип документа: contract\n",
      "Введите владельца документа: Иванов Иван\n",
      "Введите полку для хранения: 10\n",
      "Документ добавлен.\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 11-2, тип: invoice, владелец: Геннадий Покемонов, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 2\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: ad\n",
      "Введите номер документа: 346823\n",
      "Введите тип документа: contract\n",
      "Введите владельца документа: Петров Петр\n",
      "Введите полку для хранения: 55\n",
      "Такой полки не существует. Добавьте полку командой as.\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 11-2, тип: invoice, владелец: Геннадий Покемонов, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 2\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: d\n",
      "Введите номер документа: 11-2\n",
      "Документ удален.\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 2\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: d\n",
      "Введите номер документа: 77321\n",
      "Документ не найден в базе.\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 2\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: m\n",
      "Введите номер документа: 10006\n",
      "Введите номер полки: 10\n",
      "Документ перемещен.\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 10\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: m\n",
      "Введите номер документа: 28965\n",
      "Введите номер полки: 25\n",
      "Такой полки не существует. Текущий перечень полок: 1, 2, 10\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 10\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: m\n",
      "Введите номер документа: 9023\n",
      "Документ не найден в базе.\n",
      "Текущий список документов:\n",
      "№: 2207 876234, тип: passport, владелец: Василий Гупкин, полка хранения: 1\n",
      "№: 10006, тип: insurance, владелец: Аристарх Павлов, полка хранения: 10\n",
      "№: 28965, тип: contract, владелец: Иванов Иван, полка хранения: 10\n",
      "--------------------------------\n",
      "Введите команду [q - выход]: q\n"
     ]
    }
   ],
   "source": [
    "documents = [\n",
    " {'type': 'passport', 'number': '2207 876234', 'name': 'Василий Гупкин'},\n",
    " {'type': 'invoice', 'number': '11-2', 'name': 'Геннадий Покемонов'},\n",
    " {'type': 'insurance', 'number': '10006', 'name': 'Аристарх Павлов'},\n",
    "]\n",
    "\n",
    "directories = {\n",
    " '1': ['2207 876234', '11-2'],\n",
    " '2': ['10006'],\n",
    " '3': []\n",
    "}\n",
    "\n",
    "def check_correct_cmd_level_1(cmd):\n",
    "    available_cmd = ['p','s', 'l', 'q', 'as', 'ds', 'ad', 'd', 'm']\n",
    "    if cmd in available_cmd:\n",
    "        return True\n",
    "    print('Введена несуществующая команда')\n",
    "    print(f'Список существующих команд: {\", \".join(available_cmd)}')\n",
    "    return False\n",
    "\n",
    "\n",
    "def find_doc_obj_by_number_interactive():\n",
    "    \"\"\"\n",
    "    Функция интерактивно запрашивает упользователя номер документа и фильтрует список documents \n",
    "    по введеному номеру. В качестве результата функция возвращает номер докуммента и список, в котором находятся \n",
    "    только с указанным номером документы\n",
    "    \"\"\"\n",
    "    doc_number = input('Введите номер документа: ')\n",
    "    doc_object = list(filter(lambda doc_object: doc_object['number'] == doc_number, documents))\n",
    "    return doc_number, doc_object\n",
    "\n",
    "    \n",
    "def find_document_owner_interactive():\n",
    "    \"\"\"\n",
    "    Функция запускает интерактивный режим для поиска владельца документа по его номеру\n",
    "    \"\"\"\n",
    "    _, doc_object = find_doc_obj_by_number()\n",
    "    if len(doc_object) == 0:\n",
    "        print('Документ не найден в базе')\n",
    "    elif len(doc_object) > 1:\n",
    "        print(f'По номеру найдено несколько документов, нарушена логическая целостность базы, обратитесь к администратору')\n",
    "    else:\n",
    "        owner_name = doc_object[0]['name']\n",
    "        print(f'Владелец документа: {owner_name}')\n",
    "        \n",
    "    \n",
    "def find_document_shelf(doc_number):\n",
    "    \"\"\"\n",
    "    Функция находит номер полки по номеру документа.\n",
    "    doc_number - номер дкоумента\n",
    "    Возвращаемое значение - номер полки или None\n",
    "    \"\"\"\n",
    "    document_directories_list = list(filter(lambda x: doc_number in x[1], directories.items()))\n",
    "    if len(document_directories_list) > 0:\n",
    "        document_shelf = document_directories_list[0][0]\n",
    "    else:\n",
    "        document_shelf = None\n",
    "    return document_shelf\n",
    "    \n",
    "        \n",
    "\n",
    "def find_document_shelf_interactive():\n",
    "    \"\"\"\n",
    "    Функция запускает интерактивный режим для поиска полки документа по его номеру\n",
    "    \"\"\"\n",
    "    doc_number, doc_object = find_doc_obj_by_number_interactive()\n",
    "    if len(doc_object) == 0:\n",
    "        print('Документ не найден в базе')\n",
    "        return    \n",
    "    if len(doc_object) > 1:\n",
    "        print(f'По номеру найдено несколько документов, нарушена логическая целостность базы, обратитесь к администратору')\n",
    "    else:\n",
    "        document_shelf = find_document_shelf(doc_number)     \n",
    "        print(f'Номер полки: {document_shelf}')\n",
    "        \n",
    "\n",
    "def print_full_documents_info():\n",
    "    \"\"\"\n",
    "    Функция выводит сводную информацию о всех документах в базе\n",
    "    \"\"\"\n",
    "    for document in documents:\n",
    "        document_shelf_number = list(filter(lambda x: document['number'] in x[1], directories.items()))[0][0]\n",
    "        print(f\"№: {document['number']}, тип: {document['type']}, владелец: {document['name']}, полка хранения: {document_shelf_number}\")\n",
    "        \n",
    "        \n",
    "def add_shelf_interactive():\n",
    "    \"\"\"\n",
    "    Функция добавляет новую полку, если она не существует.\n",
    "    Номер полки запрашивается у пользователя.\n",
    "    \"\"\"\n",
    "    while True:\n",
    "        shelf_number = input('Введите номер полки: ')\n",
    "        if not shelf_number.isnumeric():\n",
    "            print('Номер полки введен некорректно, требуется ввести целое число')\n",
    "            continue\n",
    "        break\n",
    "        \n",
    "    current_shelf_numbers = sorted(list(directories.keys()), key=lambda x: int(x))\n",
    "    if shelf_number in current_shelf_numbers:\n",
    "        print(f'Такая полка уже существует. Текущий перечень полок: {\", \".join(current_shelf_numbers)}')\n",
    "    else:\n",
    "        directories[shelf_number] = []\n",
    "        current_shelf_numbers = sorted(list(directories.keys()), key=lambda x: int(x))\n",
    "        print(f'Полка добавлена. Текущий перечень полок: {\", \".join(current_shelf_numbers)}')\n",
    "\n",
    "        \n",
    "def remove_shelf_interactive():\n",
    "    \"\"\"\n",
    "    Функция удаляет полку, если она существует и не пуста.\n",
    "    Номер полки запрашивается у пользователя\n",
    "    \"\"\"\n",
    "    while True:\n",
    "        shelf_number = input('Введите номер полки: ')\n",
    "        if not shelf_number.isnumeric():\n",
    "            print('Номер полки введен некорректно, требуется ввести целое число')\n",
    "            continue\n",
    "        break\n",
    "    \n",
    "    current_shelf_numbers = sorted(list(directories.keys()), key=lambda x: int(x))\n",
    "    if shelf_number not in current_shelf_numbers:\n",
    "        print(f'Такой полки не существует. Текущий перечень полок: {\", \".join(current_shelf_numbers)}')\n",
    "        return\n",
    "    \n",
    "    documents_count_on_shelf = len(directories[shelf_number])\n",
    "    if documents_count_on_shelf > 0:\n",
    "        print(f'На полке есть документы, удалите их перед удалением полки. Текущий перечень полок: {\", \".join(current_shelf_numbers)}')\n",
    "        return\n",
    "    \n",
    "    del(directories[shelf_number])\n",
    "    current_shelf_numbers = sorted(list(directories.keys()), key=lambda x: int(x))\n",
    "    print(f'Полка удалена. Текущий перечень полок: {\", \".join(current_shelf_numbers)}')\n",
    "    \n",
    "    \n",
    "def add_document_interactive():\n",
    "    document_number = input('Введите номер документа: ')\n",
    "    document_type = input('Введите тип документа: ')\n",
    "    document_owner = input('Введите владельца документа: ')\n",
    "    document_shelf = input('Введите полку для хранения: ')\n",
    "    \n",
    "    current_documents_numbers = [doc_object['number'] for doc_object in documents]\n",
    "    if document_number in current_documents_numbers:\n",
    "        print('Документ с таким номером уже существует')  \n",
    "    elif document_shelf not in directories.keys():\n",
    "        print('Такой полки не существует. Добавьте полку командой as.')\n",
    "    else:\n",
    "        new_doc =  {\n",
    "                'type': document_type, \n",
    "                'number': document_number, \n",
    "                'name': document_owner\n",
    "            }\n",
    "        documents.append(new_doc)\n",
    "        directories[document_shelf].append(document_number)\n",
    "        print('Документ добавлен.')\n",
    "        \n",
    "    print('Текущий список документов:')\n",
    "    print_full_documents_info()\n",
    "    \n",
    "\n",
    "def delete_document_interactive():\n",
    "    \"\"\"\n",
    "    Функция в интерактивном режиме удаляет документ из базы.\n",
    "    Пользователь вводит номер удаляемого документа\n",
    "    \"\"\"\n",
    "    doc_number, doc_object = find_doc_obj_by_number()\n",
    "    if len(doc_object) == 0:\n",
    "        print('Документ не найден в базе.')\n",
    "    else:\n",
    "        doc_shelf = find_document_shelf(doc_number)\n",
    "        if doc_shelf is None:\n",
    "            print('Нарушение логической целостности базы, документ не найден на полке')\n",
    "        else:\n",
    "            directories[doc_shelf].remove(doc_number)\n",
    "            documents.remove(doc_object[0])\n",
    "            print('Документ удален.')\n",
    "    print('Текущий список документов:')\n",
    "    print_full_documents_info()\n",
    "    \n",
    "    \n",
    "def move_document_interactive():\n",
    "    \"\"\"\n",
    "    Функция в интерактивном режиме перемещает документ с полки на полку.\n",
    "    Пользователь вводит номер документа, а потом номер желаемой полки\n",
    "    \"\"\"\n",
    "    doc_number, doc_object = find_doc_obj_by_number()\n",
    "    if len(doc_object) == 0:\n",
    "        print('Документ не найден в базе.')\n",
    "    else:\n",
    "        new_document_shelf = input('Введите номер полки: ')\n",
    "        current_shelf_numbers = list(directories.keys())\n",
    "        if new_document_shelf not in current_shelf_numbers:\n",
    "            print(f'Такой полки не существует. Текущий перечень полок: {\", \".join(current_shelf_numbers)}')\n",
    "        if new_document_shelf in current_shelf_numbers:\n",
    "            current_document_shelf = find_document_shelf(doc_number)\n",
    "            if current_document_shelf is None:\n",
    "                print('Нарушение логической целостности базы, документ не найден на полке')\n",
    "            else:\n",
    "                directories[current_document_shelf].remove(doc_number)\n",
    "                directories[new_document_shelf].append(doc_number)\n",
    "                print('Документ перемещен.')\n",
    "    print('Текущий список документов:')\n",
    "    print_full_documents_info()\n",
    "\n",
    "\n",
    "def main():\n",
    "    while True:\n",
    "        cmd = input('Введите команду [q - выход]: ')\n",
    "        if not check_correct_cmd_level_1(cmd):\n",
    "            continue\n",
    "        if cmd == 'p':\n",
    "            find_document_owner_interactive()\n",
    "        if cmd == 's':\n",
    "            find_document_shelf_interactive()\n",
    "        if cmd == 'l':\n",
    "            print_full_documents_info()\n",
    "        if cmd == 'as':\n",
    "            add_shelf_interactive()    \n",
    "        if cmd == 'ds':\n",
    "            remove_shelf_interactive()  \n",
    "        if cmd == 'ad':\n",
    "            add_document_interactive() \n",
    "        if cmd == 'm':\n",
    "            move_document_interactive()  \n",
    "        if cmd == 'd':\n",
    "            delete_document_interactive()  \n",
    "        if cmd == 'q':\n",
    "            break\n",
    "        print('--------------------------------')\n",
    "    \n",
    "main()\n",
    "        "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
